package io.seata.sample.service;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.sample.dao.OrderDao;
import io.seata.sample.entity.Order;
import io.seata.sample.feign.AccountApi;
import io.seata.sample.feign.StorageApi;
import io.seata.sample.util.globalId.SnowFlakeGenerateIdWorker;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @author IT云清
 */
@Service("orderTCCServiceImpl")
@Slf4j
public class OrderTCCServiceImpl implements OrderTCCService{

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderTCCServiceImpl.class);

    @Autowired
    private OrderDao orderDao;
    @Resource
    private StorageApi storageApi;
    @Resource
    private AccountApi accountApi;
    private SnowFlakeGenerateIdWorker snowFlakeGenerateIdWorker =new SnowFlakeGenerateIdWorker(0L,0L);

    /**
     * 创建订单
     * @param order
     * @return
     * 测试结果：
     * 1.添加本地事务：仅仅扣减库存
     * 2.不添加本地事务：创建订单，扣减库存
     */
    @GlobalTransactional(name = "orderTccAction",rollbackFor = Exception.class)
    public void create(Order order) {
        LOGGER.info("TCC------->交易开始");
        long id = snowFlakeGenerateIdWorker.nextId();
        //本地方法l
        this.prepareCreate(null,id,order);

        //远程方法 扣减库存
        storageApi.decrease(order.getProductId(),order.getCount());

        //远程方法 扣减账户余额

        LOGGER.info("------->扣减账户开始order中");
        accountApi.decrease(order.getUserId(),order.getMoney());
        LOGGER.info("------->扣减账户结束order中");

        LOGGER.info("------->交易结束");
    }

    /**
     * 创建订单
     *
     * @param order
     * @return
     */
    @Override
    @Transactional
    public boolean prepareCreate(BusinessActionContext businessActionContext, @BusinessActionContextParameter(paramName = "orderId") Long id,Order order) {
        log.info("创建 order 第一阶段提交，修改订单状态1 - "+id);
        order.setId(id);
        orderDao.create(order);
        //事务成功，保存一个标识，供第二阶段进行判断
//        ResultHolder.setResult(getClass(), businessActionContext.getXid(), "p");
        return true;
    }

    @Override
    @Transactional
    public boolean commitCreate(BusinessActionContext businessActionContext) {
        log.info("创建 order 第二阶段提交，修改订单状态1 - "+businessActionContext.getXid());

        // 防止幂等性，如果commit阶段重复执行则直接返回
//        if (ResultHolder.getResult(getClass(), businessActionContext.getXid()) == null) {
//            return true;
//        }
//        Long orderId = (Long) businessActionContext.getActionContext("orderId");
//        long orderId = Long.parseLong(businessActionContext.getActionContext("orderId").toString());
//        orderMapper.updateStatus(orderId, 1);

        //提交成功是删除标识
        ResultHolder.removeResult(getClass(), businessActionContext.getXid());
        return true;
    }

    @Override
    @Transactional
    public boolean rollbackCreate(BusinessActionContext businessActionContext) {
        log.info("创建 order 第二阶段回滚，删除订单 - "+businessActionContext.getXid());

        //第一阶段没有完成的情况下，不必执行回滚
        //因为第一阶段有本地事务，事务失败时已经进行了回滚。
        //如果这里第一阶段成功，而其他全局事务参与者失败，这里会执行回滚
        //幂等性控制：如果重复执行回滚则直接返回
//        if (ResultHolder.getResult(getClass(), businessActionContext.getXid()) == null) {
//            return true;
//        }

        Long orderId = (Long) businessActionContext.getActionContext("orderId");
//        long orderId = Long.parseLong(businessActionContext.getActionContext("orderId").toString());
        orderDao.deleteById(orderId);

        //回滚结束时，删除标识
        ResultHolder.removeResult(getClass(), businessActionContext.getXid());
        return true;
    }

}
